package com.xgkj.diyiketang.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;



import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;

import com.xgkj.diyiketang.R;
import com.xgkj.diyiketang.security.SHA1;

/**
 * 下载客户端线程
 *    该线程服务下载apk文件，支持断点续传
 * 
 * @author houmiao.xiong
 * 
 * @time 2013-10-28 下午4:38:42
 */
public class DownloadRunnable implements Runnable{
	
	
	
	public static final int WAP_DOWNLOAD_LIMIT = 250 * 1024;
	
	
	public static final int MSGCODE_DOWNLOAD = 0x10000;
	
	
	public static final int DOWNLOAD_FAIL = MSGCODE_DOWNLOAD | 0x01;
	
	public static final int DOWNLOAD_SUCCEED = MSGCODE_DOWNLOAD | 0x02;
	
	public static final int DOWNLOAD_PROGRESS = MSGCODE_DOWNLOAD | 0x03;

    public static final int DOWNLOAD_ALREADY_EXIST = MSGCODE_DOWNLOAD | 0x04;

	
	static final String TAG = "DOWNLOAD";
	
	
	boolean mStop = false;

	int mLoadProgress = 0 ;

	private static final String USER_AGENT = "Android Mobile Wallet ";
	
	String mUrl;
	
	
	File mFolder;
	
	Context mContext;
	
	
	Handler mWatcher;
	public static final String APK_FOLDER = "diyiketang/apk";
	
	HttpClient mHttpClient;
	boolean isNewApk = false;
	
	/**
	 * 构造函数
	 * @param url
	 * @param context
	 * @param watcher
	 */
	//做假动作的构造函数
	public DownloadRunnable(String url,
			Context context,Handler watcher){
		mUrl = url;
		mContext = context;
		mFolder = EatShowSetting.getInstance(mContext).getDataFolder(APK_FOLDER);//getDownloadFolder();
		mWatcher = watcher;
        if(mHttpClient==null)
    		mHttpClient = getHttpClient();
	}
	
	
	public void stop(){
		PalLog.d(TAG, "DownloadRunnable stop");
		mStop = true;
	}
	
	
	public boolean isStop(){
		return mStop;
	}

	
	@Override
	public void run() {
		String filename = SHA1.digest(mUrl);
		if(mFolder != null){
			if(!mFolder.exists()){
				mFolder.mkdirs();
			}
		}else{
			mFolder = mContext.getFilesDir();
		}
		File tmpfile = new File(mFolder,filename+".tmp");
		File apkfile = new File(mFolder,filename+".apk");
		
		if(apkfile.exists()){
			
				if(tmpfile.exists()){
					tmpfile.delete();
				}
				notifyMessage(DOWNLOAD_ALREADY_EXIST,0, apkfile.getPath());
				return ;
		}
		
		downloadbynet(mUrl, tmpfile,apkfile);

	}
	
	public static boolean isApkExist(Context context, String url){
		String filename = SHA1.digest(url);
		File folder = EatShowSetting.getInstance(context).getDataFolder(APK_FOLDER);
		File apkfile = new File(folder,filename);
		if(apkfile != null && apkfile.exists()){
			return true;
		}
		return false;
	}
	
	
    
    protected void notifyError(int firstErrCode,int httpErrCode,int resId){
    	if (mWatcher != null && !isStop()) {
    		
//    		int detailHexErrCode = MocamConst.httpErrToShowCode(httpErrCode);
    		String errMsg = mContext.getString(resId);
//    		String format = mContext.getString(R.string.err_format_hex);
//    		errMsg =  String.format(format,errMsg,detailHexErrCode);
//    		mWatcher.handleTaskError(firstErrCode, httpErrCode, errMsg);
    		Message msg = mWatcher.obtainMessage(firstErrCode);
    		mWatcher.sendMessage(msg);
    	}
    }
    
    
    
    protected void notifyMessage(int tag,int msgCode,String apkpath){
    	if (mWatcher != null && !isStop()) {
//    		mWatcher.handleTaskCompleted(tag, msgCode, apkpath);
    		Message msg = mWatcher.obtainMessage(tag, msgCode, 0, apkpath);
    		mWatcher.sendMessage(msg);
    	}
    }
    
   
	

	
	void downloadbynet(String url,File tmpfile,File apkfile){
		
		
		HttpResponse http = null;
		if(tmpfile.exists()){
			http = tryConnectRange(url, tmpfile.length(), 0);
		}else{
			http = tryConnectRange(url, 0, 0);
		}
		
		if(http != null){
			try {
				int responseCode = http.getStatusLine().getStatusCode();
				if (responseCode != 200 && responseCode != 206) {
					notifyError(DOWNLOAD_FAIL,responseCode, R.string.client_download_fail);
					return;
				}
				
				
				long length = http.getEntity().getContentLength();
				PalLog.e(TAG, "返回长度："+length);
				if(length <= 0){
					String contentLen = null;
					Header[] headers =http.getHeaders("Content-Length");
					if(headers.length >0){
						contentLen = headers[0].toString();
					}
					if(contentLen != null && contentLen.length() >0){
						try{
							length = Integer.parseInt(contentLen);
							PalLog.e(TAG, "返回Content-Length："+length);
						}catch(Exception e){
							e.printStackTrace();
						}
					}
				}
				
				
				if(PalLog.DEBUG){
					PalLog.d(TAG, "http apk length: " + length);
				}
				
				
				
//				if(!isDishEnough(length)){
//			notifyError(MSGCODE_DOWNLOAD_FAIL,MocamConst.DISH_NOENONGH_SPACE,R.string.dish_noenough_space);
//					return;
//				}
				
				String range = null;
				Header header = http.getFirstHeader("Content-Range");
				if(header != null){
					range = header.getValue();
				}
				if(range != null){
					int endIndex = range.lastIndexOf("/");
					length = Integer.valueOf(range.substring(endIndex + 1));	
//					PalLog.e(TAG, "Range长度："+length);
					PalLog.d(TAG, "Range:" + range);
				}else{
					if(tmpfile.exists()){
						tmpfile.delete();
					}
				}
				
				InputStream is = http.getEntity().getContent();
				long notifytime = 0;
				FileOutputStream fileOutputStream = null;
				if (is != null) {
					fileOutputStream = new FileOutputStream(tmpfile,true);
					byte[] buf = new byte[1024];
					int ch = -1;
					int count = (int)tmpfile.length();
					String flowWildcard = mContext.getString(R.string.download_flow);
					String flowStr = null;
					
					while (!isStop() && (length > 0 && count < length )) {
						
						try {
							ch = is.read(buf);
							if (ch == -1) {
								break;
							}
						} catch (IOException e) {
							e.printStackTrace();
							ch = 0;
							
							try {
								is.close();
							} catch (Exception e2) {
								
							}
							is = null;
							http = tryConnectRange(url, count,length - 1);
							if (http == null) {
								break;
							} else {
								 header = http.getFirstHeader("Content-Range");
									if(header != null){
										range = header.getValue();
									}
								is = http.getEntity().getContent();
							}
						}
						if (ch > 0) {
							fileOutputStream.write(buf, 0, ch);
							count += ch;
							
							if(length > 0 ){
								int p = (int) (count * 100 / length);
								if(p != mLoadProgress &&  p - mLoadProgress >= 5){
									if(System.currentTimeMillis() - notifytime > 500){
										PalLog.e(TAG, "已下载："+count);
										flowStr = String.format(flowWildcard, count/1024,length/1024);
										notifyMessage(DOWNLOAD_PROGRESS,p,flowStr);
										notifytime = System.currentTimeMillis();
									}else{
										try {
											Thread.sleep(100);	
										} catch (Exception e) {
											
										}
									}
									mLoadProgress = p;
								}
							}else{
								
								if(System.currentTimeMillis() - notifytime > 1000){
									flowStr = String.format(flowWildcard, count/1024,length/1024);
									notifyMessage(DOWNLOAD_PROGRESS, 0,flowStr);
									notifytime = System.currentTimeMillis();
								}
								
							}
						}
					}

					if (is != null) {
						is.close();
						is = null;
					}
					
					if (fileOutputStream != null) {
						fileOutputStream.flush();
						fileOutputStream.close();
						fileOutputStream = null;
					}
					



					if(count >= length){
						tmpfile.renameTo(apkfile);
						notifyMessage(DOWNLOAD_SUCCEED,0,apkfile.getPath());
					}
				}			
				
			} catch (Exception e) {
				e.printStackTrace();
				notifyError(DOWNLOAD_FAIL,0,
						R.string.client_download_fail);	
			}
		}
		
	}
	
	

	
	
	private HttpResponse tryConnectRange(String url, long startIndex, long endIndex) {
		HttpGet result = new HttpGet(url);
		
		if(startIndex > 0 || endIndex >0 ){
			String range = "bytes=" + startIndex + "-";
			if (endIndex > startIndex) {
				range += endIndex;
			}	
			result.setHeader("RANGE", range);
			PalLog.d(TAG, "tryConnectRange:"+range);
		}
		
		int i = 0; 
		int code = 0;
		while (i < 3) {
			try { 
				HttpResponse response = mHttpClient.execute(result);
				 code = response.getStatusLine().getStatusCode();
				 Header[] head = response.getAllHeaders();
				 for(int i1 = 0 ;i1<head.length;i1++){
					// PalLog.e(TAG, "head字符串:"+head[i1].toString());
					// PalLog.e(TAG, "head值："+head[i1].getValue());
				 }
				if (code == 200 || code == 206) {
					return response;
				} else {
					Thread.sleep(1000 * 5);
				}
				i++;
			} catch (Exception e) {
				PalLog.d(TAG, "e.message " + e.getMessage());
				e.printStackTrace();
			}
			i++;
		}
		PalLog.d(TAG, "connect fail");
		notifyError(DOWNLOAD_FAIL,code,R.string.client_download_fail);
		
		return null;
	}
	
	protected HttpClient getHttpClient() {
		HttpParams params = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
		HttpConnectionParams.setSoTimeout(params, 15 * 1000);
		HttpConnectionParams.setSocketBufferSize(params, 100*1024);
		HttpProtocolParams.setUseExpectContinue(params, true);
		SchemeRegistry schReg = new SchemeRegistry();
		
		schReg.register(new Scheme("http",
								   PlainSocketFactory.getSocketFactory(),
								   80));
		
		ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,
				 schReg);
		params.setParameter(CoreProtocolPNames.USER_AGENT,USER_AGENT);

		return new DefaultHttpClient(conMgr, params);
	}
	
	
	
	private boolean isDishEnough(long size){
		String dishPath = null;
		
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
		     dishPath = Environment.getExternalStorageDirectory().getPath();
		}else{
			 dishPath = mContext.getFilesDir().getPath();
		}
		
		float apkSize = (float) size /1024;
		float freeDishSize = getFreeDiskSize(dishPath);
		
		if(PalLog.DEBUG){
	    	 PalLog.d(TAG, "apkSize:" + apkSize
	    			 + " ;freeDishSize:" + freeDishSize
	    			 + " ;dishPath:" + dishPath);
	    }
		
		if(apkSize > freeDishSize){
	    	 return false;
	     }else{
	    	 return true;
	     }
	}
	
	public static float getFreeDiskSize(String path) {
		if (path != null && path.length() > 0) {
			StatFs statFs = new StatFs(path);
			long blockSize = statFs.getBlockSize();
			long availSize = statFs.getAvailableBlocks();
			float availableSpare = (float) (availSize * blockSize) / (1024);
			return availableSpare;
		}
		return 0;
	}
	












}
